package demo.json.fastJson;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.alibaba.fastjson.annotation.JSONField;
import com.alibaba.fastjson.serializer.SerializerFeature;
import demo.java.io.IoDemo;
import demo.java.util.zip.ZipDemo;
import demo.util.CommonUtil;
import demo.vo.Teacher;
import demo.vo.TimeDemoVO;
import demo.vo.common.TimeCost;
import demo.vo.json.Student;
import demo.vo.thread.ThreadStat;
import demo.vo.tsdb.DataPoint;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

/**
 * 1，对于JSON对象与JSON格式字符串的转换可以直接用 toJSONString()这个方法。
 * <p>
 * 2，javaBean与JSON格式字符串之间的转换要用到：JSON.toJSONString(obj);
 * <p>
 * 3，javaBean与json对象间的转换使用：JSON.toJSON(obj)，然后使用强制类型转换，JSONObject或者JSONArray。
 *
 * @author hanjy
 */
public class FastJsonDemo {

    private static Logger logger = LoggerFactory.getLogger(FastJsonDemo.class);

    static String a = "{\"blacklistRule\":-9999999,\"customerId\":\"10000002113-2\",\"freezeListRule\":104,\"inalBlacklistRule\":105,\"serialNo\":\"10000002114-2\",\"userId\":\"10000002112-2\"}";

    @Test
    public void testAA() {
        StringBuilder b = new StringBuilder();

        String a = "{\"annotations\":[{\"timestamp\":1742990047986,\"value\":\"sr\"},{\"duration\":2,\"timestamp\":1742990047988,\"value\":\"ss\"}],\"appInfo\":{},\"appName\":\"a-count\",\"binaryAnnotations\":[{\"key\":\"client.ip\",\"type\":\"string\",\"value\":\"10.161.150.105\"},{\"key\":\"client.caller\",\"type\":\"string\",\"value\":\"com.ximalaya.moon.thrift.TSpankService$Iface:tAddPunishment\"},{\"key\":\"client.app\",\"type\":\"string\",\"value\":\"spank-web\"},{\"key\":\"server.result\",\"type\":\"string\",\"value\":\"success\"}],\"deviceInfo\":{\"deviceId\":\"a4b36744-0427-4cb9-bfad-802c494f70dd\",\"resolution\":{}},\"ip\":\"10.161.248.218\",\"isRowData\":false,\"isSample\":false,\"location\":{},\"monitorId\":\"5579434953591089191\",\"monitorPId\":\"5404629443660010865\",\"props\":{\"X-B3-Sampled-new\":\"true\",\"x_m_rpc_args_1\":\"[TAcountDataModel(bpId=Some(91), dimensionId=Some(2), dimensionPropertyId=Some(1192), value=433302, expiresIn=Some(-1), )]\",\"x_m_rpc_args_2\":\"TRuleData(uid=177601775, mid=a4b36744-0427-4cb9-bfad-802c494f70dd, cid=NULL, album=NULL, track=NULL, anchor=Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) ????/4.0.7 Chrome/102.0.5005.167 Electron/19.1.1 Safari/537.36 4.0.7, contactPhone=13958370788, ip=39.188.112.241, extend={fds_otp=4832947972021429555, current_album=NULL, captcha_token_check=fail, current_anchor=Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) ????/4.0.7 Chrome/102.0.5005.167 Electron\",\"x-clientIp\":\"39.188.112.241\"},\"serviceId\":\"com.ximalaya.moon.thrift.TAcountService$Iface:tInnerSet\",\"spanId\":\"275590500671709184\",\"spanName\":\"com.ximalaya.moon.thrift.TAcountService$Iface:tInnerSet\",\"spanType\":\"MAINSTAY_SERVER\",\"ts\":1742990047986}";
        JSONObject json = JSONObject.parseObject(a);
        System.out.println(JSON.toJSONString(json,true));
    }

    @Test
    public void testJSONArray() {
        String s = "[1630655076.3,\"0\"]";
        JSONArray array = JSON.parseArray(s);
        System.out.println(array.get(0).getClass() + ": " + array.get(0));
        System.out.println(array.get(1).getClass() + ": " + array.get(1));
        BigDecimal time = (BigDecimal) array.get(0);
        String timeStr = Instant.ofEpochSecond(time.longValue()).atOffset(ZoneOffset.of("+8")).toString();
        System.out.println(timeStr);
        System.out.println((String) array.get(1));
        System.out.println(Long.valueOf((String) array.get(1)));
        Instant instant = Instant.ofEpochSecond(((BigDecimal) array.get(0)).longValue());
        System.out.println(instant + " => " + instant.atOffset(ZoneOffset.of("+8")).toLocalDateTime());
        System.out.println();

    }

    @Test
    public void testJsonArray2() {
        String s = IoDemo.readFile("D:\\Stan\\workspace\\Demo\\testJava\\src\\main\\java\\demo\\json\\thread_all.json");
        System.out.println(s);
        JSONObject json = JSON.parseObject(s)
                .getJSONObject("body")
                .getJSONArray("results")
                .getJSONObject(0);
        JSONArray threadStats = json.getJSONArray("threadStats");
        ThreadStat threadStat = threadStats.getObject(0, ThreadStat.class);
        System.out.println(threadStat);
    }

    /**
     * 格式化输出
     *
     * @param object
     */
    public static void prettyPrint(JSONObject object) {
        System.err.println(JSON.toJSONString(object, SerializerFeature.PrettyFormat,
                SerializerFeature.WriteMapNullValue, SerializerFeature.WriteDateUseDateFormat));
    }

    @Test
    public void test0() {
        LocalDateTime now = LocalDateTime.now();
        logger.info(now.toString());
        logger.info(JSONObject.toJSONString(now));
        logger.info(JSONObject.toJSONString(true));

        Map<String, Object> map = new HashMap<>();
        map.put("user_id", "123456,123456789");
        map.put("task_id", "123456,123456789");
        map.put("totalCreditLine", new BigDecimal("5.33"));
        System.err.println(JSONObject.toJSONString(map));

        System.out.println(a);
        JSONObject json = JSONObject.parseObject(a);
        System.out.println(json.toJSONString());
        logger.info(JSONObject.toJSONString(json));
        logger.info(JSONObject.toJSONString(JSONObject.toJSONString(json)));
        logger.info(CommonUtil.transfer(json));
        logger.info(CommonUtil.transfer(map));
        logger.info(CommonUtil.transfer(789));

    }

    @Test
    public void test1() {
        String a = "H4sIAAAAAAAAAH2UwW7aQBCG34VrG6lSpR76AL1UKeGUQ9VDDjnkUCn3qlIRtbGxSQJxIY6hxCQu\nIPBiBMEGYvoynvXuW3Qiq1I1tiqtJev/Zsf/zOz645fSyfn5h5PPp6W3pddvXnHd4L0tNCb4Uvr6\n8l96WD4sS9vERUD56Kj8gmiVSk6AK5P7XmHqSoU/XoqRBvaYkOOzd2dJVBe1WLY9MG2Ck0gHpZYT\nfXBiCD34ocrrtXCp4SS+41pLrEL4NuCzPaW/3dQap3bM+y5BGJ9sroD1qa6MedB6z336JbDmcF1N\nnm6p3unJyYwbunQUih4mPLCoGFyKxyE0XTR9gA+6Ri+yvaBxmyUwnduM1+4o2lpYVoH3PcOKC0Ux\n3yWbXwRlJ4SHN/lUvNGRg2U68MVIlcMWpYYjqpast8TPZg49wcMtLqqbdWh2ZVujujVPdkUG+h5o\nKu8NqD4b4tx4pwu9IIl2hKbaAry60LdUN6eiscBF9YsAq4BwBfdTipwIVDNlLrA1RaO2WPlUnBrQ\nXD4PNRtnNloSJJS9YPPnm1CYOMNYGTjFO7OJ/Wdv1h653UGgFgYUzlNcTPn3ar49wjEK24Zjxx8M\nFZmbsm7+3ov1PWYoHKZUwtTo4kFDzxQ5a+wxsJs0pm7xuiVR4+/p+/QH4Ig7rvgEAAA=";
        String b = ZipDemo.ungzipString(a);
        logger.info(b);
        JSONArray jsonArray = JSONObject.parseArray(b);
        logger.info(jsonArray.toJSONString());
        JSONObject json = JSONObject.parseObject(b);
        logger.info(json.toJSONString());
    }

    @Test
    public void testBoolean() {
        System.out.println(JSON.parseObject("true", Boolean.class));
        try {
            System.out.println(JSON.parseObject("TRUE", Boolean.class));
        } catch (Exception e) {
            logger.error("", e);
        }
        try {
            System.out.println(JSON.parseObject("True", Boolean.class));
        } catch (Exception e) {
            logger.error("", e);
        }
        try {
            String a = "{'status': False, 'reason': 'unknown.'}";
            JSONObject json = JSON.parseObject(a);
            System.out.println(json.toJSONString());
        } catch (Exception e) {
            logger.error("", e);
        }
    }

    @Test
    public void toJSONString() {
        TimeDemoVO vo = new TimeDemoVO();
        String jsonStr = JSON.toJSONString(vo);
        logger.info("JSON.toJSONString(vo) = {}", jsonStr);
        Object object = JSON.parse(jsonStr);
        logger.info("JSON.parse(jsonStr) = {}", object);
        JSONObject jsonObject = (JSONObject) object;
        logger.info("JSONObject再次toJSONString = {}", JSONObject.toJSONString(jsonObject));
        logger.info("JSONObject再次toJSONString = {}", JSONObject.toJSONString(jsonObject));
        logger.info("Date toJSONString = {}", JSONObject.toJSONString(new Date()));
        logger.info("LocalDateTime toJSONString = {}", JSONObject.toJSONString(LocalDateTime.now()));
        logger.info("LocalDate toJSONString = {}", JSONObject.toJSONString(LocalDate.now()));
        logger.info("LocalTime toJSONString = {}", JSONObject.toJSONString(LocalTime.now()));
        logger.info("Object toJSONString = {}", JSONObject.toJSONString(new Object()));
        int i = 50;
        logger.info("int toJSONString = {}", JSONObject.toJSONString(i));
        logger.info("Integer toJSONString = {}", JSONObject.toJSONString(Integer.valueOf(i)));
        logger.info("Long toJSONString = {}", JSONObject.toJSONString(Long.valueOf(i)));
        logger.info("Double toJSONString = {}", JSONObject.toJSONString(Double.valueOf(i)));
        logger.info("Byte toJSONString = {}", JSONObject.toJSONString(Byte.parseByte("2")));
        Number number = Integer.valueOf(i);
        logger.info("Number toJSONString = {}", JSONObject.toJSONString(number));
        logger.info("Number toString = {}", number);
        logger.info("Null toJSONString = {}", JSONObject.toJSONString(null));
        List<Object> list = Arrays.asList(Integer.valueOf(i), LocalDateTime.now(), new Date(), vo);
        logger.info("List toJSONString = {}", JSONObject.toJSONString(list));
    }

    @Test
    public void testDateTime() {
        LocalDateTime now = LocalDateTime.now();
        String localDateTimeJson = JSON.toJSONString(now);
        System.out.println(now + " LocalDateTimetoJSONString = " + localDateTimeJson);
        LocalDateTime t2 = JSON.parseObject(localDateTimeJson, LocalDateTime.class);
        System.out.println(localDateTimeJson + " JSON.parseObject = " + t2);
        // 时间字符串转换失败，加上双引号正常
        String timeStr = "2018-10-23T20:27:48.955";
        try {
            LocalDateTime t1 = JSON.parseObject(timeStr, LocalDateTime.class);
            System.out.println(t1);
        } catch (JSONException e) {
            e.printStackTrace();
        }
        // 时间加上双引号可以正常转换
        timeStr = "\"2018-10-23T20:27:48.955\"";
        LocalDateTime t1 = JSON.parseObject(timeStr, LocalDateTime.class);
        System.out.println(timeStr + "转LocalDateTime = " + t1);

        timeStr = "\"2022-06-11T00:00:00.450Z\"";
        t1 = JSON.parseObject(timeStr, LocalDateTime.class);
        System.out.println(timeStr + "转LocalDateTime = " + t1);

        OffsetDateTime offsetDateTime = JSON.parseObject(timeStr, OffsetDateTime.class);
        System.out.println(timeStr + "转OffsetDateTime = " + offsetDateTime);

        System.out.println(offsetDateTime + " Offset转Local = " + offsetDateTime.toLocalDateTime());

    }

    @Test
    public void testOffsetDateTime() {
        String timeStr = "\"2022-06-11T00:00:00.450Z\"";
        OffsetDateTime offsetDateTime = JSON.parseObject(timeStr, OffsetDateTime.class);
        System.out.println(timeStr + "转OffsetDateTime = " + offsetDateTime);

        System.out.println(offsetDateTime + " Offset转Local = " + offsetDateTime.toLocalDateTime());

    }

    /**
     * <li>java8时间类LocalDateTime能被JSON识别
     * <li>类里没有getter方法的属性不会被转成JSON输出
     * <li>JSON的字段名和getter方法名一致
     */
    @Test
    public void testLocalDateTime() {
        TimeDemoVO vo = new TimeDemoVO(System.currentTimeMillis());
        String json = JSON.toJSONString(vo, true);
        System.out.println(json);
        TimeDemoVO tmp = JSON.parseObject(json, TimeDemoVO.class);
        System.out.println(tmp.getLocalDateTime().toString());
        String a = "{\"time\": \"2022-05-06T09:11:22.535Z\"}";
        JSONObject o = JSON.parseObject(a);
        System.out.println(o);
        System.out.println(o.getObject("time", LocalDateTime.class));
        System.out.println(o.getObject("time", OffsetDateTime.class));

    }

    @Test
    public void demoMap() {
        Map<String, String> map = new LinkedHashMap<>();
        map.put("mobile", "15030101798");
        map.put("carrier_name", "赵**");
        map.put("carrier_idcard", "132302************");
        map.put("available_balance", "810");
        String jsonStr = JSON.toJSONString(map);
        System.out.println(jsonStr);
        byte[] jsonBytes = JSON.toJSONBytes(map);
        System.out.println(jsonBytes);
        System.out.println(new String(jsonBytes, StandardCharsets.UTF_8));
        System.out.println(JSON.parseObject(jsonBytes));
        System.out.println(JSON.parseObject(jsonBytes));
    }

    @Test
    public void testToJSONByte() {
        Map<String, String> map = new LinkedHashMap<>();
        map.put("mobile", "15030101798");
        map.put("carrier_name", "赵**");
        map.put("carrier_idcard", "132302************");
        map.put("available_balance", "810");
        TimeCost t0 = new TimeCost();

        for (int i = 0; i < 10_000_000; i++) {
//            byte[] a = JSON.toJSONBytes(map);
            byte[] a = JSON.toJSONString(map).getBytes();
        }
        System.out.println("toJSONBytes() 耗时：" + t0.cost());
    }

    @Test
    public void test() {
        String a = "{\"annotations\":[{\"timestamp\":1734502059284,\"value\":\"sr\"},{\"duration\":1,\"timestamp\":1734502059285,\"value\":\"ss\"}],\"appInfo\":{\"channel\":\"ios-b1\",\"packageName\":\"com.gemd.iting\",\"version\":\"9.2.94\"},\"appName\":\"lamia-tags-web\",\"binaryAnnotations\":[],\"deviceInfo\":{\"carrierOperator\":\"未知\",\"deviceId\":\"742D0495-08F2-4A8E-89DF-C36689778359\",\"deviceName\":\"iPhone\",\"deviceType\":\"iPhone11-2\",\"macAddress\":\"742D0495-08F2-4A8E-89DF-C36689778359\",\"networkMode\":\"WIFI\",\"os\":\"iOS 18.1.1\",\"resolution\":{\"height\":\"2436\",\"width\":\"1125\"}},\"eventType\":\"OTHER\",\"ip\":\"10.161.126.216\",\"isRowData\":true,\"isSample\":false,\"location\":{\"lat\":\"22.289539337158203\",\"lng\":\"114.192626953125\",\"ts\":\"1726698852556\"},\"monitorId\":\"8871859661026668131\",\"props\":{\"xdcs.v\":\"0.0.11\",\"x_xmly_content\":\"xm_ad\",\"x-server-costtime\":\"1\",\"x-response-code\":\"200\",\"x-clientPort\":\"22026\",\"x-clientIp\":\"99.43.70.15\"},\"serviceId\":\"/v1/guards/icon/all\",\"spanId\":\"6926418731786133785\",\"spanType\":\"HTTP\",\"status\":\"on\",\"traceId\":\"5977923172537770333\",\"ts\":1734502059284,\"url\":\"/lamia-tags-web/v1/guards/icon/all\",\"userId\":\"206340690\",\"xmlyId\":\"742D0495-08F2-4A8E-89DF-C36689778359\"}";
        System.out.println(a);
        JSONObject json = JSON.parseObject(a);
        System.out.println(json);
        System.out.println(JSON.toJSONString(json, true));
    }

    /**
     * json字符串转对象
     */
    @Test
    public void parseObject() {
        Student s = JSON.parseObject(JSON_OBJ_STR, new TypeReference<Student>() {
        });
        System.out.println(s);
        Student student2 = JSON.parseObject(JSON_OBJ_STR, Student.class);
        System.out.println(student2);

        List<Student> students = JSON.parseObject(JSON_ARRAY_STR, new TypeReference<ArrayList<Student>>() {
        });
        for (Student student : students) {
            System.out.println(student);
        }
        students = JSONArray.parseArray(JSON_ARRAY_STR, Student.class);
        for (Student student : students) {
            System.out.println(student);
        }
        Teacher teacher = JSON.parseObject(COMPLEX_JSON_STR, new TypeReference<Teacher>() {
        });
        logger.info("{} ", teacher);
        String a = "\"hello fastJson\"";
        System.err.println(JSON.parseObject(a, String.class));
    }

    /**
     * 复杂json格式字符串与JSONObject之间的转换
     */
    static void testComplexJSONStrToJSONObject() {

        JSONObject jsonObject = JSON.parseObject(COMPLEX_JSON_STR);
        // JSONObject jsonObject1 =
        // JSONObject.parseObject(COMPLEX_JSON_STR);//因为JSONObject继承了JSON，所以这样也是可以的

        String teacherName = jsonObject.getString("teacherName");
        System.out.println(teacherName);
        Integer teacherAge = jsonObject.getInteger("teacherAge");
        System.out.println(teacherAge);
        JSONObject course = jsonObject.getJSONObject("course");
        System.out.println(course);
        JSONArray students = jsonObject.getJSONArray("students");
        System.out.println(students);
    }

    /**
     * json字符串-数组类型与JSONArray之间的转换
     */
    @Test
    public void testJSONStrToJSONArray() {
        JSONArray tmp = JSON.parseArray("[false,{},true]");
        for (Object object : tmp) {
            System.err.println(object + ", type = " + object.getClass());
        }
        for (int i = 0; i < tmp.size(); i++) {
            Object obj = tmp.get(i);
            if (obj instanceof Boolean) {
                System.out.println("Boolean : " + obj);
            } else if (obj instanceof JSONObject) {
                System.out.println("JSONObject : " + obj);
            } else {
                System.err.println(obj);
            }

        }
        JSONArray jsonArray = JSON.parseArray(JSON_ARRAY_STR);

        // 遍历方式1
        int size = jsonArray.size();
        for (int i = 0; i < size; i++) {
            JSONObject jsonObject = jsonArray.getJSONObject(i);
            System.out.println(jsonObject.getString("studentName") + ":" + jsonObject.getInteger("studentAge"));
        }

        // 遍历方式2
        for (Object obj : jsonArray) {
            JSONObject jsonObject = (JSONObject) obj;
            System.out.println(jsonObject.getString("studentName") + ":" + jsonObject.getInteger("studentAge"));
        }
    }

    @Test
    public void testJsonSerialize() {
        Abc a = new Abc();
        a.setName("Stan");
        a.setValue(35);
        a.setDate(new Date());
        System.out.println(JSON.toJSONString(a));
        System.out.println(JSON.toJSONString(null));
        System.out.println(JSON.toJSONBytes(null));
        System.out.println(Arrays.toString(JSON.toJSONBytes(null)));
        System.out.println(JSON.toJSONBytes(null).length);
    }

    @Test
    public void testJSONField() {
        String s = "[\n" +
                "  {\n" +
                "    \"b_originate_time\": \"2024-10-08 17:49:04\",\n" +
                "    \"status_code\": \"200005\",\n" +
                "    \"callee\": \"18217006685\",\n" +
                "    \"end_time\": \"2024-10-08 17:49:50\",\n" +
                "    \"ring_time\": \"2024-10-08 17:49:06\",\n" +
                "    \"call_id\": \"145612850080^132359605080\",\n" +
                "    \"duration\": \"0\",\n" +
                "    \"voice_type\": \"voice\",\n" +
                "    \"caller\": \"075589424251\",\n" +
                "    \"b_end_time\": \"2024-10-08 17:49:50\",\n" +
                "    \"b_duration\": 0,\n" +
                "    \"status_msg\": \"未接通-原因运营商未返回\",\n" +
                "    \"originate_time\": \"2024-10-08 17:49:04\",\n" +
                "    \"b_ring_time\": \"2024-10-08 17:49:06\",\n" +
                "    \"out_id\": \"\",\n" +
                "    \"toll_type\": \"DOMESTIC\"\n" +
                "  }\n" +
                "]";
        System.out.println(s);
        List<AliVoiceReport> list = JSON.parseArray(s, AliVoiceReport.class);
        System.err.println(list);
        System.out.println(JSON.toJSONString(list, true));
    }

    class Abc {
        private String name;

        @JSONField(name = "age")
        private Integer value;

        @JSONField(serialize = false)
        private Date date;

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public Integer getValue() {
            return value;
        }

        public void setValue(Integer value) {
            this.value = value;
        }

        public Date getDate() {
            return date;
        }

        public void setDate(Date date) {
            this.date = date;
        }

    }

    // json字符串-简单对象型
    private static final String JSON_OBJ_STR = "{\"studentName\":\"lily\",\"studentAge\":12}";
    // json字符串-数组类型
    private static final String JSON_ARRAY_STR = "[{\"studentName\":\"lily\",\"studentAge\":12},{\"studentName\":\"lucy\",\"studentAge\":15}]";
    // 复杂格式json字符串
    private static final String COMPLEX_JSON_STR = "{\"teacherName\":\"crystall\",\"teacherAge\":27,\"course\":{\"courseName\":\"english\",\"code\":1270},\"students\":[{\"studentName\":\"lily\",\"studentAge\":12},{\"studentName\":\"lucy\",\"studentAge\":15}]}";

}
